﻿using System;
using UnityEngine;
using UnityEngine.UI;

namespace ZyGame
{
    public enum ControllerState
    {
        None = -1,
        Move,
        Rotate,
        Scale,
        Pen,
    }
    public class CameraCtrl : Singleton<CameraCtrl>
    {
        private WindowsCameraController windowsCamera;
        public ControllerState state
        {
            get
            {
                return windowsCamera.type;
            }
        }

        public CameraCtrl()
        {
#if UNITY_WEBGL
            windowsCamera = new WindowsCameraController();
            Client.Tools.AddUpdate(Update);
#endif
        }
        public void SetTarget(GameObject gameObject)
        {
            if (windowsCamera is null)
            {
                return;
            }
            windowsCamera.target = gameObject.transform;
        }

        private void Update()
        {
            if (windowsCamera is null)
            {
                return;
            }
            windowsCamera.LateUpdate();
        }

        public void LockControllerType(ControllerState type)
        {
            if (windowsCamera is null || state == type)
            {
                return;
            }

            windowsCamera.SetControllerType(type);
        }

        public void SetControllrtType(ControllerState type)
        {
            if (windowsCamera is null)
            {
                return;
            }
            windowsCamera.SetControllerType(type);
        }

        internal void Hide(ControllerState pen)
        {
            if (windowsCamera is null)
            {
                return;
            }
            windowsCamera.SetActived(pen, false);
        }

        internal void Show(ControllerState pen)
        {
            if (windowsCamera is null)
            {
                return;
            }
            windowsCamera.SetActived(pen, true);
        }
    }
    public class WindowsCameraController
    {
        public Transform target;    // 相机需要以目标物为中心
        public Vector3 mouseLeapPose = Vector3.zero;
        public Vector3 mousePos = Vector3.zero;
        public float rotateSpeed = 2;
        public float movementSpeed = 0.02F;
        public float nowCamEulerX = 0;
        public float maxAngle = 90;
        public float minAngle = -90;
        public float maxFieldOfView = 40;
        public float minFieldOfView = 1;
        public float zoomSpeed = 0.1f;
        public Vector3 rotationTargetPosition = Vector3.zero;
        public bool isKeyDown = false;
        public ControllerState type = ControllerState.None;
        public bool active = false;
        private Sprite[] btn_selection_state_sprites;
        private Sprite[] btn_notselection_state_sprites;
        private Image[] btn_images;

        public WindowsCameraController()
        {
            btn_images = new Image[4];
            btn_images[0] = GameObject.Find("Function/move").GetComponent<Image>();
            btn_images[1] = GameObject.Find("Function/rotate").GetComponent<Image>();
            btn_images[2] = GameObject.Find("Function/scale").GetComponent<Image>();
            btn_images[3] = GameObject.Find("Function/pen").GetComponent<Image>();
            btn_selection_state_sprites = new Sprite[4];
            btn_notselection_state_sprites = new Sprite[4];

            btn_selection_state_sprites[(int)ControllerState.Move] = Resources.Load<Sprite>("icon_Move_1");
            btn_selection_state_sprites[(int)ControllerState.Rotate] = Resources.Load<Sprite>("icon_Spin_1");
            btn_selection_state_sprites[(int)ControllerState.Scale] = Resources.Load<Sprite>("icon_Zoom_1");
            btn_selection_state_sprites[(int)ControllerState.Pen] = Resources.Load<Sprite>("icon_Brush_1");

            btn_notselection_state_sprites[(int)ControllerState.Move] = Resources.Load<Sprite>("icon_Move");
            btn_notselection_state_sprites[(int)ControllerState.Rotate] = Resources.Load<Sprite>("icon_Spin");
            btn_notselection_state_sprites[(int)ControllerState.Scale] = Resources.Load<Sprite>("icon_Zoom");
            btn_notselection_state_sprites[(int)ControllerState.Pen] = Resources.Load<Sprite>("icon_Brush");
            mainCamera = Camera.main;
            rightVector = Vector3.right;
            upVector = Vector3.up;
            zeroVector = Vector3.zero;
        }
        internal void SetActived(ControllerState state, bool active)
        {
            if (state == ControllerState.None)
            {
                return;
            }
            btn_images[(int)state].gameObject.SetActive(active);
        }


        public void SetControllerType(ControllerState type)
        {
            this.type = this.type == type ? ControllerState.Move : type;
            btn_images[0].sprite = this.type == ControllerState.Move ? btn_selection_state_sprites[(int)ControllerState.Move] : btn_notselection_state_sprites[(int)ControllerState.Move];
            btn_images[1].sprite = this.type == ControllerState.Rotate ? btn_selection_state_sprites[(int)ControllerState.Rotate] : btn_notselection_state_sprites[(int)ControllerState.Rotate];
            btn_images[2].sprite = this.type == ControllerState.Scale ? btn_selection_state_sprites[(int)ControllerState.Scale] : btn_notselection_state_sprites[(int)ControllerState.Scale];
            btn_images[3].sprite = this.type == ControllerState.Pen ? btn_selection_state_sprites[(int)ControllerState.Pen] : btn_notselection_state_sprites[(int)ControllerState.Pen];

        }
        public void LateUpdate()
        {
            if (Input.GetMouseButtonDown(0))
            {
                isActive = !Physics.Raycast(Input.mousePosition, Vector3.forward);
                return;
            }

            if (!isActive)
            {
                return;
            }

            if (type == ControllerState.Move) HandleInputType0();
            else if (type == ControllerState.Rotate) HandleInputType1();
            else if (type == ControllerState.Scale) HandleInputType2();
        }

        private bool isActive;
        private Camera mainCamera;
        private Vector3 rightVector;
        private Vector3 upVector;
        private Vector3 zeroVector;

        private void Update()
        {
            HandleInput();
        }

        private void HandleInput()
        {

        }

        private void HandleInputType0()
        {
            mainCamera.transform.position -= GetAxisValue("Mouse X") * Time.timeScale * movementSpeed * mainCamera.transform.right;
            mainCamera.transform.position -= GetAxisValue("Mouse Y") * Time.timeScale * movementSpeed * mainCamera.transform.up;
        }

        private void HandleInputType1()
        {
            var offset = new Vector2(GetAxisValue("Mouse X"), GetAxisValue("Mouse Y")) * Time.timeScale * rotateSpeed;

            mouseLeapPose = Vector2.Lerp(mouseLeapPose, offset, 9f * Time.timeScale);

            var targetPosition = target != null ? target.transform.position : zeroVector;
            mainCamera.transform.RotateAround(targetPosition, upVector, mouseLeapPose.x);
            nowCamEulerX = nowCamEulerX - mouseLeapPose.y * rotateSpeed;
            if (nowCamEulerX > maxAngle || nowCamEulerX < minAngle)
            {

                nowCamEulerX = nowCamEulerX + mouseLeapPose.y * rotateSpeed;
                mouseLeapPose.y = 0;
                return;
            }

            if (Mathf.Abs(-mouseLeapPose.y * rotateSpeed) < 0.02f)
                return;
            Camera.main.transform.RotateAround(Vector3.zero, Camera.main.transform.right, -mouseLeapPose.y * rotateSpeed);
        }

        private void HandleInputType2()
        {
            var delta = GetAxisValue("Mouse Y") != 0 ? GetAxisValue("Mouse Y") : GetAxisValue("Mouse X");
            var zoom = delta * zoomSpeed;
            var fov = Mathf.Clamp(mainCamera.fieldOfView - zoom, minFieldOfView, maxFieldOfView);

            mainCamera.fieldOfView = fov;
        }

        private float GetAxisValue(string axisName) => Input.GetMouseButton(0) ? Input.GetAxis(axisName) : 0;


        // 角度限制方法
        static float ClampAngle(float angle, float min, float max)
        {
            if (angle < -360)
                angle += 360;
            if (angle > 360)
                angle -= 360;
            return Mathf.Clamp(angle, min, max);
        }
    }
}